// 版权归Go作者所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现浮点到字符串的转换函数。
// 它正在密切关注strconv/ftoa中相应的实现
// 。去吧，但对浮动进行了修改和简化。

package big

import (
	"bytes"
	"fmt"
	"strconv"
)

// Text根据给定的格式和精度，将浮点数x转换为字符串。格式为：
// 
// /'e'-d.dddddde±dd，十进制指数，至少两个（可能为0）指数位数
// /'e'-d.dddddde±dd，十进制指数，至少两个（可能为0）指数位数
// /'f'-ddddd。dddd，对于大指数，没有像‘e’这样的指数，比如‘f’或者像‘e’一样的指数，比如‘f’或者像‘e’一样的指数，比如‘f’或者像‘e’一样的指数，比如‘f’或者像‘e’一样的指数。ddddp±dd，十六进制尾数，两个指数的十进制幂
// /'p'-0x。dddp±dd，十六进制尾数，两个指数的十进制幂（非标准）
// /'b'-DDDD P±dd，十进制尾数，两个指数的十进制幂（非标准）
// 
// 两个指数格式的幂，尾数以标准化形式打印：
// 
// /'x'十六进制尾数在[1,2]中，或0 
// /'p'十六进制尾数在[½,1]中，或0 
// /'b'十进制整数尾数使用x.Prec（）bits或0 
// 
// 请注意，大多数其他语言和库都使用“x”形式。
// 
// 如果格式是另一个字符，文本将返回一个“%”，后跟
// 无法识别的格式字符。
// 
// precision prec控制数字的数量（不包括指数）
// 以“e”、“e”、“f”、“g”、“g”和“x”格式打印。
// 对于“e”、“e”、“f”和“x”，它是小数点后的位数。
// 对于“g”和“g”，它是总位数。负精度选择
// 使用x.Prec（）尾数位唯一标识值x所需的最小小数位数。
// 对于'b'和'p'格式，prec值被忽略。
func (x *Float) Text(format byte, prec int) string {
	cap := 10 // TODO（gri）在这里确定一个好的/更好的值
	if prec > 0 {
		cap += prec
	}
	return string(x.Append(make([]byte, 0, cap), format, prec))
}

// 字符串格式x，比如x.Text（'g'，10）。
// /（必须显式调用字符串，浮点。格式不支持%s动词。）
func (x *Float) String() string {
	return x.Text('g', 10)
}

// Append将x.Text生成的浮点数x的字符串形式追加到buf，并返回扩展缓冲区。
func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
	// sign 
	if x.neg {
		buf = append(buf, '-')
	}

	// Inf 
	if x.form == inf {
		if !x.neg {
			buf = append(buf, '+')
		}
		return append(buf, "Inf"...)
	}

	// 选择简单格式
	switch fmt {
	case 'b':
		return x.fmtB(buf)
	case 'p':
		return x.fmtP(buf)
	case 'x':
		return x.fmtX(buf, prec)
	}

	// 算法：
	// 1）将浮点转换为多精度十进制
	// 2）四舍五入到所需精度
	// 3）读取数字并格式化

	// 1）将浮点转换为多精度十进制
	var d decimal // =0.0 
	if x.form == finite {
		// x！=0 
		d.init(x.mant, int(x.exp)-x.mant.bitLen())
	}

	// 2）四舍五入到所需精度
	shortest := false
	if prec < 0 {
		shortest = true
		roundShortest(&d, x)
		// 最短表示模式的精度。
		switch fmt {
		case 'e', 'E':
			prec = len(d.mant) - 1
		case 'f':
			prec = max(len(d.mant)-d.exp, 0)
		case 'g', 'G':
			prec = len(d.mant)
		}
	} else {
		// 适当四舍五入
		switch fmt {
		case 'e', 'E':
			// 小数点前一位和小数点后的位数
			d.round(1 + prec)
		case 'f':
			// 小数点前和小数点后的位数
			d.round(d.exp + prec)
		case 'g', 'G':
			if prec == 0 {
				prec = 1
			}
			d.round(prec)
		}
	}

	// 3）读出数字并格式化
	switch fmt {
	case 'e', 'E':
		return fmtE(buf, fmt, prec, d)
	case 'f':
		return fmtF(buf, prec, d)
	case 'g', 'G':
		// 以%e格式修剪尾部小数点
		eprec := prec
		if eprec > len(d.mant) && len(d.mant) >= d.exp {
			eprec = len(d.mant)
		}
		// /%e，如果转换的指数
		// 小于-4或大于或等于精度。
		// 如果精度是最短的，则使用eprec=6表示
		// 此决定。
		if shortest {
			eprec = 6
		}
		exp := d.exp - 1
		if exp < -4 || exp >= eprec {
			if prec > len(d.mant) {
				prec = len(d.mant)
			}
			return fmtE(buf, fmt+'e'-'g', prec-1, d)
		}
		if prec > d.exp {
			prec = len(d.mant)
		}
		return fmtF(buf, max(prec-d.exp, 0), d)
	}

	// 未知格式
	if x.neg {
		buf = buf[:len(buf)-1] // 符号过早添加-再次删除
	}
	return append(buf, '%', fmt)
}

func roundShortest(d *decimal, x *Float) {
	// 如果尾数为零，数字为零-立即停止
	if len(d.mant) == 0 {
		return
	}

	// 方法：区间[x-1/2ulp，x+1/2ulp]中的所有数字
	// （可能不包括）四舍五入到x，以给定的精度为x。
	// 以十进制形式计算下限和上限，并找到最短的十进制数d，使下限<=d<=上限。

	// TODO（gri）strconv/ftoa。do在某些情况下描述了一种快捷方式。
	// 看看我们是否也可以在这里使用它（调整后的形式）。

	// 1）计算x的归一化尾数mant和指数exp，这样，mant的lsb对应于1/2 ulp，以获得
	// x的精度（即，对于mant，我们需要x.prec+1位）。
	mant := nat(nil).set(x.mant)
	exp := int(x.exp) - mant.bitLen()
	s := mant.bitLen() - int(x.prec+1)
	switch {
	case s < 0:
		mant = mant.shl(mant, uint(-s))
	case s > 0:
		mant = mant.shr(mant, uint(+s))
	}
	exp += s
	// x=mant*2**exp，其中lsb（mant）==x的1/2 ulp。prec 

	// 2）通过减去1/2 ulp计算下限。
	var lower decimal
	var tmp nat
	lower.init(tmp.sub(mant, natOne), exp)

	// 3）通过添加1/2 ulp计算上限。
	var upper decimal
	upper.init(tmp.add(mant, natOne), exp)

	// 只有当
	// 原始尾数为偶数时，上下界才是可能的输出，因此即使是四舍五入
	// 也会四舍五入到原始尾数，而不是相邻尾数。
	inclusive := mant[0]&2 == 0 // 测试位1，因为原始尾数被移位了1 

	// 现在我们可以计算出所需的最小位数。
	// 一直往前走，直到d从上到下区分开来。
	for i, m := range d.mant {
		l := lower.at(i)
		u := upper.at(i)

		// 如果lower有不同的数字
		// 或者lower包含在内，并且正好是
		// 向下四舍五入的结果（即，我们已经到达lower的最后一位），则可以向下四舍五入（截断）。
		okdown := l != m || inclusive && i+1 == len(lower.mant)

		// 如果upper有不同的数字，且upper 
		// 包含或upper大于四舍五入的结果，则可以进行四舍五入。
		okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))

		// 如果两种方法都可以，那就转到最近的一种。
		// 如果可以只做一个，那就去做。
		switch {
		case okdown && okup:
			d.round(i + 1)
			return
		case okdown:
			d.roundDown(i + 1)
			return
		case okup:
			d.roundUp(i + 1)
			return
		}
	}
}

// /%e:d.ddddd e±dd 
func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
	// 第一位
	ch := byte('0')
	if len(d.mant) > 0 {
		ch = d.mant[0]
	}
	buf = append(buf, ch)

	// /。更多数字
	if prec > 0 {
		buf = append(buf, '.')
		i := 1
		m := min(len(d.mant), prec+1)
		if i < m {
			buf = append(buf, d.mant[i:m]...)
			i = m
		}
		for ; i <= prec; i++ {
			buf = append(buf, '0')
		}
	}

	// /e±
	buf = append(buf, fmt)
	var exp int64
	if len(d.mant) > 0 {
		exp = int64(d.exp) - 1 // /-1，因为第一个数字是在“.”之前打印的
	}
	if exp < 0 {
		ch = '-'
		exp = -exp
	} else {
		ch = '+'
	}
	buf = append(buf, ch)

	// dd。。。d 
	if exp < 10 {
		buf = append(buf, '0') // 至少两个指数位数
	}
	return strconv.AppendInt(buf, exp, 10)
}

// /%f:ddddddd。ddddd 
func fmtF(buf []byte, prec int, d decimal) []byte {
	// 整数，根据需要用零填充
	if d.exp > 0 {
		m := min(len(d.mant), d.exp)
		buf = append(buf, d.mant[:m]...)
		for ; m < d.exp; m++ {
			buf = append(buf, '0')
		}
	} else {
		buf = append(buf, '0')
	}

	// 分数
	if prec > 0 {
		buf = append(buf, '.')
		for i := 0; i < prec; i++ {
			buf = append(buf, d.at(d.exp+i))
		}
	}

	return buf
}

// fmtB以尾数“p”指数
// 的格式将x字符串附加一个十进制尾数和一个二进制指数，或者0“如果x为零，则返回扩展缓冲区。尾数被规范化，以便在二进制中使用x.Prec（）位。
// 表示。
// 忽略x的符号，并且x不能是Inf。
// （调用fmtB之前，调用方处理Inf）
func (x *Float) fmtB(buf []byte) []byte {
	if x.form == zero {
		return append(buf, '0')
	}

	if debugFloat && x.form != finite {
		panic("non-finite float")
	}
	// x！=0 

	// 调整尾数以精确使用x。prec位
	m := x.mant
	switch w := uint32(len(x.mant)) * _W; {
	case w < x.prec:
		m = nat(nil).shl(m, uint(x.prec-w))
	case w > x.prec:
		m = nat(nil).shr(m, uint(w-x.prec))
	}

	buf = append(buf, m.utoa(10)...)
	buf = append(buf, 'p')
	e := int64(x.exp) - int64(x.prec)
	if e >= 0 {
		buf = append(buf, '+')
	}
	return strconv.AppendInt(buf, e, 10)
}

// fmtX以“0x1”格式追加x字符串尾数“p”指数
// 带十六进制尾数和二进制指数，或“0x0p0”如果x为零，
// 并返回扩展缓冲区。
// 对非零尾数进行归一化，使1.0<=尾数<2.0。wen jian efg
func (x *Float) fmtX(buf []byte, prec int) []byte {
	if x.form == zero {
		buf = append(buf, "0x0"...)
		if prec > 0 {
			buf = append(buf, '.')
			for i := 0; i < prec; i++ {
				buf = append(buf, '0')
			}
		}
		buf = append(buf, "p+00"...)
		return buf
	}

	if debugFloat && x.form != finite {
		panic("non-finite float")
	}

	// 将尾数取整为n位
	var n uint
	if prec < 0 {
		n = 1 + (x.MinPrec()-1+3)/4*4 // 将MinPrec取整为1模4 
	} else {
		n = 1 + 4*uint(prec)
	}
	// n%4==1 
	x = new(Float).SetPrec(n).SetMode(x.mode).Set(x)

	// 调整尾数以精确使用n位
	m := x.mant
	switch w := uint(len(x.mant)) * _W; {
	case w < n:
		m = nat(nil).shl(m, n-w)
	case w > n:
		m = nat(nil).shr(m, w-n)
	}
	exp64 := int64(x.exp) - 1 // 避免环绕

	hm := m.utoa(16)
	if debugFloat && hm[0] != '1' {
		panic("incorrect mantissa: " + string(hm))
	}
	buf = append(buf, "0x1"...)
	if len(hm) > 1 {
		buf = append(buf, '.')
		buf = append(buf, hm[1:]...)
	}

	buf = append(buf, 'p')
	if exp64 >= 0 {
		buf = append(buf, '+')
	} else {
		exp64 = -exp64
		buf = append(buf, '-')
	}
	// 强制至少两个指数数字，以匹配fmt。
	if exp64 < 10 {
		buf = append(buf, '0')
	}
	return strconv.AppendInt(buf, exp64, 10)
}

// fmtP以“0x”格式追加x的字符串尾数“p”指数
// 带有十六进制尾数和二进制指数，如果x为零，则为“0”，返回扩展缓冲区。
// 尾数被标准化为0.5<=0。尾数<1.0。
// x的符号被忽略，x不能是Inf。
// （调用者在调用fmtP之前处理Inf。）
func (x *Float) fmtP(buf []byte) []byte {
	if x.form == zero {
		return append(buf, '0')
	}

	if debugFloat && x.form != finite {
		panic("non-finite float")
	}
	// x！=0 

	// 删除尾随的0个单词早期
	// （无需转换为十六进制0，稍后进行修剪）
	m := x.mant
	i := 0
	for i < len(m) && m[i] == 0 {
		i++
	}
	m = m[i:]

	buf = append(buf, "0x."...)
	buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
	buf = append(buf, 'p')
	if x.exp >= 0 {
		buf = append(buf, '+')
	}
	return strconv.AppendInt(buf, int64(x.exp), 10)
}

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

var _ fmt.Formatter = &floatZero // *浮点必须执行fmt。格式化程序

// 格式化程序实现fmt。格式化程序。它接受浮点数的所有常规
// 格式（“b”、“e”、“e”、“f”、“f”、“
// /'g”、“g”、“x”）以及“p”和“v”。参见（*浮动）。
// 对“p”的解释。“v”格式的处理方式类似于“g”。
// 格式还支持以数字表示的最小精度规格
// 输出字段宽度，以及符号控制的格式标志
// /'+'和''，'0'表示空格或零填充，
// 和'-'表示左对齐或右对齐。详见fmt包
// 。
func (x *Float) Format(s fmt.State, format rune) {
	prec, hasPrec := s.Precision()
	if !hasPrec {
		prec = 6 // 默认精度为'e'，'f'
	}

	switch format {
	case 'e', 'E', 'f', 'b', 'p', 'x':
		// 无需任何操作
	case 'F':
		// /（*浮点）。文本不支持“F”；类似于'f'的句柄
		format = 'f'
	case 'v':
		// 类似于'g'的句柄
		format = 'g'
		fallthrough
	case 'g', 'G':
		if !hasPrec {
			prec = -1 // 默认精度为'g'，'g'
		}
	default:
		fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
		return
	}
	var buf []byte
	buf = x.Append(buf, byte(format), prec)
	if len(buf) == 0 {
		buf = []byte("?") // 永远不会发生，但不要崩溃
	}
	// len（buf）>0 

	var sign string
	switch {
	case buf[0] == '-':
		sign = "-"
		buf = buf[1:]
	case buf[0] == '+':
		// /+Inf 
		sign = "+"
		if s.Flag(' ') {
			sign = " "
		}
		buf = buf[1:]
	case s.Flag('+'):
		sign = "+"
	case s.Flag(' '):
		sign = " "
	}

	var padding int
	if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
		padding = width - len(sign) - len(buf)
	}

	switch {
	case s.Flag('0') && !x.IsInf():
		// 0-左侧填充
		writeMultiple(s, sign, 1)
		writeMultiple(s, "0", padding)
		s.Write(buf)
	case s.Flag('-'):
		// 右侧填充
		writeMultiple(s, sign, 1)
		s.Write(buf)
		writeMultiple(s, " ", padding)
	default:
		writeMultiple(s, " ", padding)
		writeMultiple(s, sign, 1)
		s.Write(buf)
	}
}
